/**
 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef GE_OP_IMPL_REGISTRY_BASE_H
#define GE_OP_IMPL_REGISTRY_BASE_H

#include <cstddef>
#include "register/op_impl_kernel_registry.h"

namespace ge {
struct OpImplRegistryBase : public OpImplKernelRegistry {
    virtual ~OpImplRegistryBase() = default;
    virtual const OpImplFunctions *GetOpImpl(const ge::char_t *op_type) const = 0;
};

class GRAPH_API_EXPORT OpImplRegistry : public OpImplRegistryBase {
public:
    using OpType = std::string;
    static OpImplRegistry &GetInstance();
    OpImplFunctions &CreateOrGetOpImpl(const ge::char_t *op_type);
    const OpImplFunctions *GetOpImpl(const ge::char_t *op_type) const override;
    const std::map<OpType, OpImplFunctions> &GetAllTypesToImpl() const;
    std::map<OpType, OpImplFunctions> &GetAllTypesToImpl();

private:
    std::map<OpType, OpImplFunctions> types_to_impl_;
    uint8_t reserved_[40] = {0U};  // Reserved field, 32+8, do not directly use when only 8-byte left
};
class OpImplRegister;
class OpImplRegister {
public:
    explicit OpImplRegister(const ge::char_t *op_type);
    OpImplRegister &Tiling(OpImplKernelRegistry::TilingKernelFunc tiling_func, size_t max_tiling_data_size = 2048);
    template <typename T>
    OpImplRegister &TilingParse(OpImplKernelRegistry::KernelFunc tiling_parse_func)
    {
        functions_.tiling_parse = tiling_parse_func;
        functions_.compile_info_creator = CreateCompileInfo<T>;
        functions_.compile_info_deleter = DeleteCompileInfo<T>;
        return *this;
    }
    template <typename T>
    OpImplRegister &TilingParse(OpImplKernelRegistry::TilingParseFunc tiling_parse_func)
    {
        functions_.tiling_parse = reinterpret_cast<OpImplKernelRegistry::KernelFunc>(tiling_parse_func);
        functions_.compile_info_creator = CreateCompileInfo<T>;
        functions_.compile_info_deleter = DeleteCompileInfo<T>;
        return *this;
    }

private:
    template <typename T, typename std::enable_if<(!std::is_array<T>::value), int32_t>::type = 0>
    static void *CreateCompileInfo()
    {
        return new T();
    }
    template <typename T>
    static void DeleteCompileInfo(void *const obj)
    {
        delete reinterpret_cast<T *>(obj);
    }
    template <size_t MaxLen>
    static void *CreateDynamicLenTilingData()
    {
        return TilingData::CreateCap(MaxLen).release();
    }
    OpImplRegister &PrivateAttrImpl(const ge::char_t *private_attr, ge::AnyValue private_attr_av);

private:
    const ge::char_t *op_type_;
    OpImplRegistry::OpImplFunctions &functions_;
    uint8_t reserved_[40] = {0U};  // Reserved field, 32+8, do not directly use when only 8-byte left
};

struct TypesToImpl {
    const char *op_type;
    gert::OpImplKernelRegistry::OpImplFunctions funcs;
};

size_t GetRegisteredOpNum(void);
int32_t GetOpImplFunctions(TypesToImpl *impl, size_t impl_num);

}  // namespace ge

#endif
